package com.sfeir.android.friendapps;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.sfeir.android.friendapps.controller.AppsController;
import com.sfeir.android.friendapps.model.User;

/**
 * FriendList Activity
 * 
 * @author Nazim
 * 
 */
public class FriendListActivity extends Activity {
	private ListView itemList;
	private User u = null;
	private Context baseContext = null;
	private Intent intent = null;
	private String mail = "";
	private String listId = "";
	private ImageButton refreshBtn;
	private boolean isFirstUse;
	private SharedPreferences shared;
	private SharedPreferences.Editor editor;
	private UpdateAsyncTask locTask = null;

	/**
	 * Creating the view
	 * 
	 * @see #initView()
	 * @see #initData()
	 * @see #updatingDataList()
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fa_main);

		initView();
		initData();
		// updatingDataList();
		updatingWithAsyncTask();
	}

	/**
	 * Init the Async Task
	 * 
	 * @see UpdateAsyncTask
	 */
	protected void updatingWithAsyncTask() {
		if (locTask == null) {
			locTask = new UpdateAsyncTask();
			Void v = null;
			locTask.execute(v);
		}
	}

	/**
	 * Updating list data, by retreiving information from server, and updating
	 * the list
	 * 
	 * @see #endLoading()
	 * @see #settingList()
	 * @see #startLoading()
	 */
	// protected void updatingDataList() {
	//
	// final Handler handler = new Handler() {
	// public void handleMessage(final Message msg) {
	// endLoading();
	// if (msg.what == 0) {
	// } else {
	// settingList();
	// }
	// }
	// };
	// final Thread checkUpdate = new Thread() {
	// public void run() {
	// startLoading();
	// AppsController app = new AppsController();
	// try {
	// u = app.retrieveUser(mail, listId);
	// } catch (Exception e) {
	// handler.sendEmptyMessage(0);
	// return;
	// }
	// handler.sendEmptyMessage(1);
	// }
	// };
	// checkUpdate.start();
	// }

	/**
	 * This method init view elements before using and Refresh Button
	 * 
	 * @see #updatingDataList()
	 * @see #goToMarket(int)
	 */
	protected void initView() {
		refreshBtn = (ImageButton) findViewById(R.id.btn_title_refresh);
		refreshBtn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				updatingWithAsyncTask();
				// updatingDataList();
			}
		});

		itemList = (ListView) findViewById(R.id.listviewitem);
		itemList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> a, View v, int position,
					long id) {

				goToMarket(position, a.getItemAtPosition(position));
			}
		});
	}

	/**
	 * Init all necessary variable
	 * 
	 * @see #fillEmptyList()
	 * @see #fillExistingList()
	 */
	protected void initData() {
		u = new User();
		baseContext = getBaseContext();
		intent = this.getIntent();
		mail = intent.getExtras().getString("mail");
		listId = intent.getExtras().getString("listId");

		shared = getSharedPreferences("Friend-Apps", 0);
		editor = shared.edit();
		isFirstUse = shared.getBoolean("isFirstUse", true);
		// isFirstUse = true;
		if (isFirstUse == true) {
			fillEmptyList();
			isFirstUse = false;
			editor.putBoolean("isFirstUse", isFirstUse);
			editor.commit();
		} else {
			fillExistingList();
		}

	}

	/**
	 * Changing the current view to the market view
	 * 
	 * @param position
	 *            : The position of the clicked list item
	 * @see #getAppPackage(String)
	 */
	protected void goToMarket(final int position, final Object clickedItem) {
		String packageName = "";
		if (u != null) {
			Log.i("Friends", u.getAppLink().get(position));
			packageName = getAppPackage(u.getAppLink().get(position));
		}
		Log.i("Friends", packageName);
		try {
		    Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
		    startActivity(intent);
		} catch (Exception e) {
		    e.printStackTrace();
		    Intent intent = new Intent(Intent.ACTION_VIEW);
		    Uri uri = Uri.parse("market://details?id=" + packageName);
		    intent.setData(uri);
		    startActivity(intent);
		}
	}

	/**
	 * Convert the app values to an unique string. This string will be stored in
	 * the Shared Preference
	 * 
	 * @param appName
	 *            Application name
	 * @param appLink
	 *            Application Market Link
	 * @param appImgLink
	 *            Application Image Link
	 * @return The formated string
	 */
	private String convertAppValues(String appName, String appLink,
			String appImgLink) {
		return new StringBuilder().append(appName).append(" - ")
				.append(appLink).append(" - ").append(appImgLink).toString();
	}

	/**
	 * Convert the apps contained in the list to an unique string
	 * 
	 * @param appsLink
	 *            the applications links
	 * @return The formated string
	 */
	private String convertToString(ArrayList<String> appsLink) {
		ArrayList<String> appsPackage = new ArrayList<String>(appsLink.size());

		for (String link : appsLink)
			appsPackage.add(getAppPackage(link));

		StringBuilder str = new StringBuilder();

		for (String app : appsPackage)
			str.append(app + " - ");

		str.delete(str.length() - 3, str.length());
		Log.i("FriendsList", str.toString());
		return str.toString();

	}

	/**
	 * @see #isAlreadyDownloaded()
	 */
	protected void fillExistingList() {
		isAlreadyDownloaded();
	}

	/**
	 * Getting all already downloaded applications list Init the list with
	 * actual data
	 * 
	 * @see #searchFileInArray(ArrayList, String)
	 */
	protected void isAlreadyDownloaded() {
		ArrayList<File> fileList = new ArrayList<File>();
		String extStorageDirectory = Environment.getExternalStorageDirectory()
				.toString();
		String meteoDirectory_path = extStorageDirectory + "/Friend-apps";
		File outputFile = new File(meteoDirectory_path, "/");
		if (outputFile.exists()) {
			for (File f : outputFile.listFiles()) {
				if (shared.getString(f.getName(), null) != null) {
					Log.i("isAlreadyDownloaded", f.getName());
					fileList.add(f);
				}
			}

			String res = shared.getString(listId + " - " + mail, null);

			u.setListeId(listId);
			u.setMail(mail);

			ArrayList<String> appName = new ArrayList<String>();
			ArrayList<String> appImg = new ArrayList<String>();
			ArrayList<String> appLnk = new ArrayList<String>();
			if (res != null) {
				ArrayList<HashMap<String, String>> item = new ArrayList<HashMap<String, String>>();
				HashMap<String, String> map;

				String[] tmp = res.split(" - ");
				for (int i = 0; i < tmp.length; ++i) {
					Log.i("Split Values", tmp[i]);
					String app = shared.getString(tmp[i], null);
					if (app != null) {
						map = new HashMap<String, String>();
						String[] tmp2 = app.split(" - ");
						Log.i("Split Values 2", tmp2[0]);
						Log.i("Split Values 2", tmp2[1]);
						appName.add(tmp2[0]);
						map.put("titre", tmp2[0]);
						appImg.add(searchFileInArray(fileList, tmp[i]));
						map.put("img", searchFileInArray(fileList, tmp[i]));
						appLnk.add(tmp[1]);
						map.put("link", tmp[1]);
						item.add(map);

						SimpleAdapter mSchedule = new SimpleAdapter(
								baseContext, item, R.layout.fa_item,
								new String[] { "img", "titre" }, new int[] {
										R.id.imgItem, R.id.titreItem });

						itemList.setAdapter(mSchedule);

					}
				}
			}

			u.setAppImg(appImg);
			u.setAppLink(appLnk);
			u.setAppName(appName);
		}
	}

	/**
	 * Search already downloaded app in the apps list
	 * 
	 * @param fileList
	 *            the list of downloaded files
	 * @param appId
	 *            the searched application
	 * @return
	 */
	private String searchFileInArray(ArrayList<File> fileList, String appId) {
		for (File f : fileList) {
			if (f.getName().equals(appId))
				return f.getAbsolutePath();
		}
		return null;
	}

	/**
	 * Fill Empty list with Friend Apps
	 */
	protected void fillEmptyList() {
		ArrayList<HashMap<String, String>> listItem = new ArrayList<HashMap<String, String>>();

		HashMap<String, String> map;

		map = new HashMap<String, String>();
		map.put("titre", "Friend Apps");
		String link = "http://friend-apps.appspot.com";
		map.put("img", String.valueOf(R.drawable.favicon));
		map.put("link", link);
		listItem.add(map);

		SimpleAdapter mSchedule = new SimpleAdapter(baseContext, listItem,
				R.layout.fa_item, new String[] { "img", "titre" }, new int[] {
						R.id.imgItem, R.id.titreItem });

		itemList.setAdapter(mSchedule);

	}

	/**
	 * Clean the list
	 */
	protected void cleanItemList() {
		if (isFirstUse == true)
			itemList.setAdapter(null);
	}

	/**
	 * Download an image from an url
	 * 
	 * @param url
	 *            the image url
	 * @param path
	 *            the path where the image will be storeed
	 * @return the image absoluth path
	 */
	protected String loadImageFromWebOperations(String url, String path) {
		try {
			String extStorageDirectory = Environment
					.getExternalStorageDirectory().toString();
			String meteoDirectory_path = extStorageDirectory + "/Friend-apps";
			File outputFile = new File(meteoDirectory_path, "/");
			outputFile.mkdirs();
			InputStream is = (InputStream) new URL(url).getContent();
			Log.i("loadImageFromWebOperations", path);
			// System.out.println(path);
			File f = new File(path);

			f.createNewFile();
			FileOutputStream fos = new FileOutputStream(f);

			try {

				byte[] b = new byte[100];
				int l = 0;
				while ((l = is.read(b)) != -1)
					fos.write(b, 0, l);

			} catch (Exception e) {
				e.printStackTrace();
			}

			return f.getAbsolutePath();
		} catch (Exception e) {
			System.out.println("Exc=" + e);
			return null;

		}
	}

	/**
	 * Getting the application package from the link
	 * 
	 * @param link
	 *            the application market link
	 * @return the application package
	 */
	protected String getAppPackage(final String link) {
		String tmp[] = link.split("id=");
		if (tmp.length > 1)
			tmp = tmp[1].split("&");
		Log.i("tmp0 = ", tmp[0]);
		return tmp[0];
	}

	/**
	 * Check if an image is already in the friends app directory
	 * 
	 * @param packageName
	 *            the application package name
	 * @return the file absoluth path
	 */
	protected String isAlreadyExist(final String packageName) {
		String extStorageDirectory = Environment.getExternalStorageDirectory()
				.toString();
		String meteoDirectory_path = extStorageDirectory + "/Friend-apps";
		File outputFile = new File(meteoDirectory_path, "/");
		File file = new File(outputFile, packageName);
		if (file.exists() == true)
			return file.getAbsolutePath();
		return null;
	}

	/**
	 * display refresh icon
	 */
	protected void startLoading() {
		Log.i("Loading", "start");
		findViewById(R.id.btn_title_refresh).setVisibility(View.GONE);
		findViewById(R.id.title_refresh_progress).setVisibility(View.VISIBLE);
	}

	/**
	 * disable refresh icon
	 */
	protected void endLoading() {
		Log.i("Loading", "end");
		cleanItemList();
		findViewById(R.id.btn_title_refresh).setVisibility(View.VISIBLE);
		findViewById(R.id.title_refresh_progress).setVisibility(View.GONE);

	}

	/**
	 * The Async Task Error
	 * 
	 * @author Nazim
	 * 
	 */
	public class UpdateAsyncTask extends AsyncTask<Void, Void, Boolean> {

	    	@Override
	    	protected void onPreExecute() {
	    	    startLoading();
	    	}
	    
		@Override
		protected Boolean doInBackground(Void... arg0) {
			AppsController app = new AppsController();
			try {
				u = app.retrieveUser(mail, listId);
			} catch (Exception e) {
				return false;
			}
			return true;
		}

		protected void onProgressUpdate(Void... progress) {
		}

		protected void onPostExecute(Boolean result) {
			Log.i("AsyncTask", "On Post Execute");
			if (result == true)
				settingList();
			endLoading();
			locTask = null;
		}

		/**
		 * Setting List adapter and init the list
		 * 
		 * @see #fillList(ArrayList)
		 */
		protected void settingList() {
			ArrayList<HashMap<String, String>> listItem = new ArrayList<HashMap<String, String>>();
			fillList(listItem);
			SimpleAdapter mSchedule = new SimpleAdapter(baseContext, listItem,
					R.layout.fa_item, new String[] { "img", "titre" },
					new int[] { R.id.imgItem, R.id.titreItem });
			itemList.setAdapter(mSchedule);
		}

		/**
		 * Fill the list
		 * 
		 * @param listItem
		 *            : The filling list
		 * @return true if the filling success else false
		 * @see #createSharedPreference(User)
		 * @see #ImageOperations(Context, String, String)
		 * @see #getAppPackage(String)
		 * @see #downloadFile(String, String, String)
		 */
		protected boolean fillList(
				final ArrayList<HashMap<String, String>> listItem) {
			HashMap<String, String> map;
			if (u != null)
				createSharedPreference(u);
			if (u != null && u.getAppName() != null) {
				for (int i = 0; i < u.getAppName().size(); ++i) {
					map = new HashMap<String, String>();
					map.put("titre", u.getAppName().get(i));
					Drawable d = ImageOperations(getBaseContext(), u
							.getAppImg().get(i), u.getAppName().get(i));
					Log.i("Friends", String.valueOf(d));
					String link = getAppPackage(u.getAppLink().get(i));
					map.put("img",
							downloadFile(u.getAppImg().get(i), u.getAppName()
									.get(i), link));
					map.put("link", u.getAppLink().get(i));
					listItem.add(map);
				}
			} else {
				Log.i("Friend", "user is null");
			}
			return false;
		}

		/**
		 * Create the shared preferences values
		 * 
		 * @param u
		 *            : the user object
		 * @see #convertToString(ArrayList)
		 * @see #convertAppValues(String, String, String)
		 */
		protected void createSharedPreference(final User u) {
			if (shared.getString(u.getListeId() + " - " + u.getMail(), null) == null) {
				editor.putString(u.getListeId() + " - " + u.getMail(),
						convertToString(u.getAppLink()));
				editor.commit();
			} else if (shared.getString(u.getListeId(), null) != null) {
				editor.putString(u.getListeId() + " - " + u.getMail(),
						convertToString(u.getAppLink()));
				editor.remove(u.getListeId());
				editor.commit();
			} else {
				Log.i("List => ", Integer.toString(u.getAppLink().size()));
				String str = shared.getString(
						u.getListeId() + " - " + u.getMail(), null);
				String[] tmp = str.split(" - ");
				Log.i("Tmp => ", Integer.toString(tmp.length));
				if (tmp.length != u.getAppLink().size()) {
					editor.putString(u.getListeId(),
							convertToString(u.getAppLink()));
					editor.commit();
				}
			}

			for (int i = 0; i < u.getAppLink().size(); ++i) {
				String appString = getAppPackage(u.getAppLink().get(i));
				String appName = u.getAppName().get(i);
				String appLink = u.getAppLink().get(i);
				String appImgLink = u.getAppLink().get(i);
				if (shared.getString(appString, null) == null) {
					editor.putString(appString,
							convertAppValues(appName, appLink, appImgLink));
					editor.commit();
				} else {
				}

			}

		}

		/**
		 * Saving the image on the SD Card
		 * 
		 * @param ctx
		 *            application context
		 * @param url
		 *            application market url
		 * @param saveFilename
		 *            application saveFileName
		 * @return the image drawable
		 */
		protected Drawable ImageOperations(Context ctx, String url,
				String saveFilename) {
			try {
				InputStream is = (InputStream) this.fetch(url);
				Drawable d = Drawable.createFromStream(is, "src");
				return d;
			} catch (MalformedURLException e) {
				e.printStackTrace();
				return null;
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			}
		}

		/**
		 * Fetch an url content
		 */
		protected Object fetch(String address) throws MalformedURLException,
				IOException {
			URL url = new URL(address);
			Object content = url.getContent();
			return content;
		}

		/**
		 * Download the file from market if necessary
		 * 
		 * @param fileUrl
		 *            the file market url
		 * @param appName
		 *            the application name
		 * @param link
		 *            the application link
		 * @return the saved application path
		 * @see #isAlreadyExist(String)
		 * @see #saveToSD(Bitmap, String)
		 */
		protected String downloadFile(String fileUrl, String appName,
				String link) {
			String absolutePath;
			if ((absolutePath = isAlreadyExist(link)) != null) {
				Log.i("FriendListActivity : No download need", absolutePath);
				return absolutePath;
			}
			Bitmap bm = null;
			try {
				URL aURL = new URL(fileUrl);
				URLConnection conn = aURL.openConnection();
				conn.connect();
				InputStream is = conn.getInputStream();

				BufferedInputStream bis = new BufferedInputStream(is);

				bm = BitmapFactory.decodeStream(bis);

				bis.close();
				is.close();
				Log.e("dl", "OK");
			} catch (IOException e) {
				Log.e("Erreur", "Erreur IO");
			}
			return saveToSD(bm, link);
		}

		/**
		 * Save the downloaded file in the SD Card
		 * 
		 * @param bm
		 *            The bitmap image
		 * @param image_name
		 *            the image name
		 * @return the saved image absoluth path
		 */
		protected String saveToSD(Bitmap bm, String image_name) {

			String extStorageDirectory = Environment
					.getExternalStorageDirectory().toString();
			String meteoDirectory_path = extStorageDirectory + "/Friend-apps";
			File outputFile = new File(meteoDirectory_path, "/");
			if (outputFile.exists() == false)
				outputFile.mkdirs();
			OutputStream outStream = null;
			File file = new File(outputFile, image_name);
			if (file.exists() == false) {
				try {
					outStream = new FileOutputStream(file);
					bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
					outStream.flush();
					outStream.close();

				} catch (FileNotFoundException e) {
					e.printStackTrace();
					Log.i("Hub", "FileNotFoundException: " + e.toString());
				} catch (IOException e) {
					e.printStackTrace();
					Log.i("Hub", "IOException: " + e.toString());
				}
			} else {
				Log.i("FriendListActivity", "File already exist");
			}
			return file.getAbsolutePath();
		}

	}
}
